package com.core.base.provider;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import com.core.base.annotation.Action;
import com.core.util.ClassUtil;
import com.core.util.ResourceUtils;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.ConfigurationProvider;
import com.opensymphony.xwork2.config.ConfigurationUtil;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
import com.opensymphony.xwork2.config.entities.PackageConfig;
import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.util.location.LocatableProperties;

/***
 * struts注解配置类提供类
 * 主要用于Action通用注解配置,如全局拦截器
 * 
 * @author Administrator
 *
 */
public class StrutsAnnotationConfigurationProvider implements
		ConfigurationProvider {
	// 是否使用spring
		private static boolean IS_USE_SPRING = true;

		/** 默认的每个Action的继承  
		 *  注意,struts.xml的配置文件要相应进行设置
		 **/
		public static final String DEFAULT_PARENT = "global-default";
		
		private static final Logger log = LoggerFactory.getLogger(StrutsAnnotationConfigurationProvider.class);

		private Configuration configuration;

		public void destroy() {
		}

		public void init(Configuration configuration) throws ConfigurationException {
			if (log.isDebugEnabled()) {
				log.debug("进入struts2的注解配置提供类..");
			}
			this.configuration = configuration;
		}

		private void configOneClass(String className, Configuration configuration) {
			Class<?> actionClazz = null;
			try {
				actionClazz = ClassUtil.forName(className);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}

			if ((actionClazz.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT) {
				log.debug("忽略. 类 [{0}] 是抽象的.",className);
				return;
			}

			if (!ActionSupport.class.isAssignableFrom(actionClazz)) {
				String msg = "忽略. 类 [{0}] 不是继承 ActionSupport类";
				log.debug(msg,className);
				return;
			}
			log.debug("加载xwork元数据配置Action类 [" + className + "]");

			processActionInMethod(className, configuration, actionClazz);
		}

		private void processActionInMethod(String className, Configuration configuration,
				Class<?> actionClazz) {
			String packageName = className;
			String actionClass = null;
			String namespace = "";
			String actionName = null;
			String methodName = null;
			String interceptorStackName = null;
			String packageExtends = DEFAULT_PARENT;
			
			Action action = actionClazz.getAnnotation(Action.class);
			// 所有的方法
			List<Method> methods = ClassUtil.getAllDeclaredMethod(actionClazz);

			PackageConfig.Builder packageBuilder = new PackageConfig.Builder(
					packageName);
			for (Method m : methods) {
				if (!isActionMethod(m)) {
					continue;
				}
				
				if(!m.isAnnotationPresent(Action.class)
	                    || !checkMethodSignature(m)){
					continue;
				}
				
				methodName = m.getName();

				// 拦截器stack的名字
				interceptorStackName = action.interceptorStack();

				List<PackageConfig> parents = ConfigurationUtil.buildParentsFromString(configuration, packageExtends);

				Action methodAction = m.getAnnotation(Action.class);

				namespace = methodAction.namespace();
				
				// action名
				actionName = methodAction.name();
				if("".equals(actionName)){
					actionName = m.getDeclaringClass().getSimpleName()+"_"+m.getName();
				}

				// 方法名
				methodName = m.getName();
				if(IS_USE_SPRING){
					if(!"".equals(action.className())){
						actionClass = action.className();
					}
					if(!"".equals(methodAction.className())){
						actionClass = methodAction.className();
					}
				} else {
					actionClass = actionClazz.getName();
				}

				// 配置Action
				ActionConfig.Builder actionBuilder = new ActionConfig.Builder(
						packageName, actionName, actionClass)
						.methodName(methodName);

				if (log.isDebugEnabled()) {
					String msg = "添加一个action,packageName=[{0}],ActionClass=[{1}],NameSpace=[{2}],ActionName=[{3}],methodName=[{4}]";
					msg = MessageFormat
							.format(msg, packageName, actionClass, namespace,
									actionName, methodName);
					log.debug(msg);
				}

				// 拦截器配置
				buildInterceptors(actionBuilder,interceptorStackName,parents);
				
				// 添加action到一个package(包)中
				packageBuilder.addActionConfig(actionName, actionBuilder.build());
				
				// 设置命名空间
				packageBuilder.namespace(namespace);
				
				// 设置父类
				packageBuilder.addParents(parents);

			}

			// 添加package中总配置中
			configuration.addPackageConfig(packageName, packageBuilder.build());
		}
		
		private void buildInterceptors(ActionConfig.Builder actionBuilder, String interceptorStackName,List<PackageConfig> parents){
			for (PackageConfig pc : parents) {
				Object interceptorConfig = pc
						.getInterceptorConfig(interceptorStackName);
				if (interceptorConfig == null
						|| !(interceptorConfig instanceof InterceptorStackConfig)) {
					continue;
				}

				Collection<InterceptorMapping> interceptors = ((InterceptorStackConfig) interceptorConfig)
						.getInterceptors();
				actionBuilder.addInterceptors((List<InterceptorMapping>) interceptors);

				log.debug("添加拦截器栈，名称为:" + interceptorStackName + ",列表为: " + interceptors);
				break;
			}
		}

		public ResultTypeConfig getResultConfig(List<PackageConfig> parentsPackageConfigs,String resultType){
			if(parentsPackageConfigs == null){
				return null;
			}
			for(PackageConfig pc : parentsPackageConfigs){
				ResultTypeConfig resultTypeConfig = pc.getResultTypeConfigs().get(resultType);
				if(resultTypeConfig != null){
					return resultTypeConfig;
				}
				if(pc.getParents() != null){
					return getResultConfig(pc.getParents(),resultType);
				}
			}
			return null;
		}
		
		/**
		 * 是否合法的Action 方法,只是以go和do开头的才认为是合法Action
		 * 
		 * @param m
		 * @return
		 */
		private boolean isActionMethod(Method m) {
			if (m == null) {
				return false;
			}
			// 如果类的名字不是以Action结果的
			if (!m.getDeclaringClass().getName().endsWith("Action")) {
				return false;
			}
			return true;
		}

		public boolean needsReload() {
			return false;
		}

		public void register(ContainerBuilder builder, LocatableProperties props)
				throws ConfigurationException {
		}

		public void loadPackages() throws ConfigurationException {
			// 得到所有的Action的className
			LinkedList<String> classNames = ClassFinder
					.getClassName("classpath*:com/**/action/*Action");
			if (log.isDebugEnabled()) {
				for (String s : classNames) {
					log.debug(String.format("找到的Action类[%s]", s));
				}
			}

			for (String className : classNames) {
				configOneClass(className, this.configuration);
			}
		}

		private static class ClassFinder {
			public static LinkedList<String> getClassName(String regString) {
				LinkedList<String> resouceArray = new LinkedList<String>();
				regString = regString.trim();
				if (!regString.endsWith(".class")) {
					regString = regString + ".class";
				}
				try {
					Resource[] rs = ResourceUtils.getClassPathResourceByPattern(regString);

					resouceArray = new LinkedList<String>();
					for (Resource c : rs) {
						String className = ClassUtil.getClassNameByURL(c.getURL());
						resouceArray.add(className);
					}
				} catch (IOException e) {
					log.error("error in find resource", e);
				}
				return resouceArray;
			}
		}

		private boolean checkMethodSignature(Method method) {
	        return (method!=null && method.getModifiers()==Modifier.PUBLIC && 
	        		String.class.equals(method.getReturnType()) && (method.getParameterTypes().length == 0));
	    }
}
